package cn.com.nes.site.modules.sale;

import cn.com.nes.common.exception.BusinessException;
import cn.com.nes.common.exception.MissBusinessParameterException;
import cn.com.nes.common.util.ExcelUtils;
import cn.com.nes.mybatis.agent.crm.entity.Opportunity;
import cn.com.nes.site.controller.crm.opportunity.vo.ExportTemplateExcelOfEndCustomerVO;
import cn.com.nes.site.entity.iot.CascadeCell;
import cn.com.nes.site.handle.CascadeWriteHandler;
import cn.com.nes.site.modules.sale.bo.SaleBO;
import cn.com.nes.site.modules.sale.bo.SaleDetailBO;
import cn.com.nes.site.modules.sale.dto.SaleDetailDTO;
import cn.com.nes.site.service.crm.opportunity.CrmOpportunityService;
import cn.com.nes.site.service.logs.ImportLogDetailsService;
import cn.com.nes.site.service.logs.ImportLogsService;
import cn.com.nes.site.service.system.region.XzqhService;
import cn.com.nes.site.service.system.region.dto.XzqhDTO;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 销售业务逻辑层
 */
@Slf4j
@Service
public class SaleService {

    @Resource
    SaleServiceFactoty saleServiceFactoty;

    @Resource
    private ImportLogDetailsService importLogDetailsService;

    @Resource
    private ImportLogsService importLogsService;

    @Resource
    private CrmOpportunityService crmOpportunityService;

    @Resource
    private XzqhService xzqhService;

    public CrmOpportunityService getCrmOpportunityService() {
        return crmOpportunityService;
    }

    public ImportLogDetailsService getImportLogDetailsService() {
        return importLogDetailsService;
    }

    public ImportLogsService getImportLogsService() {
        return importLogsService;
    }

    public void exportEndCustomerSaleTemplateExcel(ExportTemplateExcelOfEndCustomerVO vo,
            HttpServletResponse response) throws Exception {

        List<String> coverageArea = crmOpportunityService.getCoverageArea(vo.getOpportunityUuid());
        if (CollUtil.isNotEmpty(coverageArea)) {
            List<String> notMatchAreaCode = vo.getXzqhdmList()
                    .stream()
                    .filter(xzqhdm -> !coverageArea.contains(xzqhdm))
                    .collect(Collectors.toList());
            List<XzqhDTO> xzqhListByXzqhdmList = xzqhService.getXzqhListByXzqhdmList(notMatchAreaCode);
            List<String> areaNames = xzqhListByXzqhdmList.stream().map(XzqhDTO::getXzqhmc).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(areaNames)) {
                throw new BusinessException(areaNames + "不在项目设置范围内");
            }
        }

        // 获取下拉框内容
        List<CascadeCell> cascadeCellList = crmOpportunityService.getEndCustomerSaleTemplateExcelHeaderCellContent(vo);
        // 自定义级联下拉框处理器
        SheetWriteHandler sheetWriteHandler = new CascadeWriteHandler(cascadeCellList);
        List<XzqhDTO> xzqhDTOList = xzqhService.getXzqhListByXzqhdmList(vo.getXzqhdmList());
        XzqhDTO xzqhDTO = xzqhDTOList.get(0);

        // 输出文件
        Opportunity opportunity = crmOpportunityService.getOpportunity(vo.getOpportunityUuid());
        String excelFileName = opportunity.getOpportunityName() + "-" + xzqhDTO.getXzqhmc() + "-终端客户销售导入模板";
        ExcelUtils.exportExcel(crmOpportunityService.getEndCustomerSaleTemplateExcelHeaders(vo.getOpportunityUuid()), sheetWriteHandler, response, "导入信息", excelFileName);
    }

    /**
     * Saves the provided sale business object, encapsulating both default and specific sale handling procedures.
     * This method ensures transactional integrity, rolling back if any exception occurs during processing.
     * It first invokes the default sale handling logic and subsequently determines whether specific
     * handling is required based on the attributes of the sale business object.
     * @param saleBO The non-null {@link SaleBO} instance containing the sale details to be processed.
     *               This includes information like sale type, associated business objects, and flags indicating
     *               special conditions like the installation of photovoltaic systems.
     * @throws Exception If the input saleBO is null, or if any business logic exception is encountered,
     *                   causing the entire transaction to be rolled back.
     */
    @Transactional(rollbackFor = Exception.class)
    public void saleSaveHandle(SaleBO saleBO) throws Exception {
        if (ObjectUtil.isEmpty(saleBO)) {
            throw new MissBusinessParameterException("saleBO must not be null");
        }

        defaultSaleHandle(saleBO);

        specificSaleHandle(saleBO);
    }

    /**
     * Processes a batch of sales business objects in a transactional manner.
     * This method iterates over the provided list of {@link SaleBO} instances,
     * invoking the {@link #saleSaveHandle(SaleBO)} method for each item to ensure
     * that all sales within the batch are saved or none are, maintaining data integrity.
     * @param saleBOS A list of {@link SaleBO} objects representing the sales to be processed.
     *                The list must not be empty.
     * @throws Exception If any exception occurs during the processing of sales, causing the transaction to rollback.
     */
    @Transactional(rollbackFor = Exception.class)
    public void saleSaveHandle(List<SaleBO> saleBOS) throws Exception {
        if (CollUtil.isEmpty(saleBOS)) {
            throw new MissBusinessParameterException("saleBOS must not be empty");
        }
        log.debug("SaleService saveHandle saleBOS size:{}", saleBOS.size());

        for (SaleBO saleBO : saleBOS) {
            saleSaveHandle(saleBO);
        }
    }

    /**
     * Handles specific sales business logic if required by the {@link SaleBO}.
     * This method checks if the sale instance requires special handling through
     * {@link SaleBO#isHandleSpecificSale()} and proceeds accordingly.
     * @param saleBO The {@link SaleBO} instance containing details to determine if specific sale handling is needed.
     */
    private void specificSaleHandle(SaleBO saleBO) {
        if (!saleBO.isHandleSpecificSale()) {
            log.debug("不执行的特定销售业务处理...");
            return;
        }
        log.debug("执行特定的销售业务处理...");
    }

    /**
     * Handles the default sale process by delegating to the appropriate sale handle based on the provided sale type.
     * @param saleBO The SaleBO instance containing the details required to process the sale.
     * @throws Exception If an error occurs during the handling of the sale.
     */
    private void defaultSaleHandle(SaleBO saleBO) throws Exception {
        log.debug("SaleService defaultSaleHandle...");

        SaleHandle saleHandle = saleServiceFactoty.getSaleHandle(saleBO.getSaleType());

        saleHandle.handleSaleSave(saleBO);
    }

    /**
     * 查询销售详情
     */
    public SaleDetailDTO getSaleDetail(SaleDetailBO saleDetailBO) {
        if (StrUtil.isBlank(saleDetailBO.getOpportunityUuid())) {
            throw new MissBusinessParameterException("opportunityUuid must not null");
        }

        SaleHandle saleHandle = saleServiceFactoty.getSaleHandle(saleDetailBO.getSaleType());
        try {
            return saleHandle.getSaleDetail(saleDetailBO);
        } catch (Exception e) {
            log.error("查询销售详情异常,异常信息:{}", e.getMessage());
            e.printStackTrace();
        }
        return new SaleDetailDTO();
    }

}
